local uu       = require('modules.commhm.utils')
local mis_config   = require('mis_config')
local log       = require("modules.commhm.log")
local mis_data     = nil
local mis_log      = nil
local mis_bridge   = nil
local mis_common   = nil
local t_retCode    = nil

local ngx = ngx
local pairs = pairs
local table = table
local math = math
local math_max = math.max
local math_min = math.min
local tonumber = tonumber
local tostring = tostring
local table_insert = table.insert
local string_match = string.match
local string_sub    = string.sub

local this = {
    s_name = string.match(debug.getinfo(1).short_src, '.*/(.*).lua');	-- 模块名称
}

this.CODE_MIN_LEN = 9

-- 说明：模块包含
-- 参数：模块表
this.modules_include = function(t_moddules)
    mis_config   = t_moddules.mis_config
    mis_data     = t_moddules.mis_data
    mis_log      = t_moddules.mis_log
    mis_bridge   = t_moddules.mis_bridge
    mis_common   = t_moddules.mis_common
    t_retCode    = mis_config.t_retCode
end

this.new_share_code = function(uin, len)
    local t = {
        "0" ,"1" ,"2" ,"3","4","5","6","7","8","9",
        --"a" ,"b","c","d","e","f","q","h" ,"i","i","k","l","m","n" ,"o","p","q","r","s","t", "u" ,"y" , "w" ,"x" , "y","z",
        "A", "B" ,"C","D" ,"E","F","G" ,"H" ,"I","J","K" , "L", "M" ,"N" ,"O" ,"P","Q","R" , "S" , "T" , "U" , "V" , "W" , "X" , "Y" , "Z"
    }

    local s_code = string.format('%X', uin)
    for i =1, len do
        s_code = s_code .. t[math.random(#t)]
    end

    return s_code
end

this.is_valid_time = function(time1, time2, expire)
    return time1 + expire > time2
end

this.special_exchange_max = function(t_codeConf, n_uin, n_mapId)
    local n_max

    for k, v in pairs(t_codeConf or {}) do
        --if v.n_uin == n_uin and v.n_mapId == n_mapId then
        if v.n_uin == n_uin then
            n_max = v.n_maxExchange
        end
    end

    return n_max
end

--------------------------------------------------------------
-- 说明：gift业务前置检测
-- 返回：n					状态码
--		ts 					描述
this.pre_map_share = function()
    local t_params  		= ngx.ctx.t_params
    local s_type			= t_params.mission_type
    local t_taskConf 		= mis_data.t_share_mission[s_type]
    local n_nowtime 		= mis_data.offset_now_v2(t_taskConf)
    local s_file            = s_type .. '_code'

    if t_taskConf.n_status ~= mis_config.t_workStatus.n_ENABLE then
        mis_log.day(s_file,"pre_map_share status disable|" .. t_params.uin .. '|' .. s_type)
        return t_retCode.n_OPER_ERR, 'share_mission disable'
    end

    -- 活动有效期间
    if n_nowtime < t_taskConf.t_conf.n_startTime or n_nowtime > t_taskConf.t_conf.n_endTime then
        mis_log.day(s_file,"pre_map_share out of time|" .. t_params.uin .. '|' .. s_type)
        return t_retCode.n_OPER_ERR, 'Activity is out of validity!'
    end

    -- 渠道控制
    if uu.tableNotEmpty(t_taskConf.t_conf.t_apiids) then
        local b_valid_apiid  = false
        local n_apiid  =  tonumber(t_params.apiid or 0)

        for _, v in pairs(t_taskConf.t_conf.t_apiids) do
            if v and tonumber(v) == n_apiid then
                b_valid_apiid = true
                break
            end
        end
        if not b_valid_apiid then
            mis_log.day(s_file,"pre_map_share apiid is invalid|" .. t_params.uin .. '|' .. s_type .. "|" .. n_apiid)
            return t_retCode.n_OPER_ERR, 'apiid is invalid'
        end
    end

    if uu.tableNotEmpty(t_taskConf.t_conf.t_noapiids) then
        local b_valid_apiid  = false
        local n_apiid  =  tonumber(t_params.apiid or 0)

        for _, v in pairs(t_taskConf.t_conf.t_apiids) do
            if v and tonumber(v) == n_apiid then
                b_valid_apiid = true
                break
            end
        end
        if b_valid_apiid then
            mis_log.day(s_file,"pre_map_share noapiid is invalid|" .. t_params.uin .. '|' .. s_type .. "|" .. n_apiid)
            return t_retCode.n_OPER_ERR, 'apiid is invalid - ' .. n_apiid
        end
    end

    -- 版本号控制
    local n_l = mis_common.version_to_number(t_params.ver or 0)
    local n_r = t_taskConf.t_conf.n_version_min
    if n_l < n_r then
        mis_log.day(s_file,"pre_map_share version too low|" .. t_params.uin .. '|' .. s_type .. "|" .. n_l)
        return t_retCode.n_OPER_ERR, 'version too low'
    end

    return t_retCode.n_OK
end


--------------------------------------------------------------
-- 说明：请求分享码
-- 返回：n					状态码
--		ts 					描述
this.request_map_share_code = function()
    local t_params 			= ngx.ctx.t_params
    local n_uin 			= t_params.uin
    local s_type			= t_params.mission_type
    local t_taskConf 		= mis_data.t_share_mission[s_type]
    local n_now				= mis_data.offset_now_v2(t_taskConf)
    local n_mapId           = t_params.mapId
    local t_shareCode		= t_taskConf.t_conf.t_shareCode or {}
    local s_file            = s_type .. '_code'
    local n_code, s_desc, s_code, n_verify, n_specialMax
    local t_user, t_userData

    t_user = mis_data.get_user()
    n_code, t_userData = t_user:get_share_mission_data(s_type)
    if n_code ~= t_retCode.n_OK then
        log.day_list(s_file ,"request_map_share_code", "get user data error", s_type, n_uin, n_code, uu.to_str(t_userData))
        return n_code, 'get user data error'
    end

    t_userData.share_code = t_userData.share_code or {}
    t_userData.share_code[s_type] = t_userData.share_code[s_type] or {}

    -- 移除过期的邀请码
    for k, v in pairs(t_userData.share_code[s_type]) do
        if v.ctime and not this.is_valid_time(v.ctime, n_now, t_shareCode.n_expire) then
            t_userData.share_code[s_type][k] = nil
        end
    end

    if t_userData.share_code[s_type][n_mapId] then
        s_code      = t_userData.share_code[s_type][n_mapId].code
        n_verify    = t_userData.share_code[s_type][n_mapId].verify or 0
        return t_retCode.n_OK, { code = s_code , verify = n_verify}
    end

    -- 生成邀请码
    if not s_code then
        s_code, s_desc = this.new_share_code(n_uin, t_shareCode.n_suffix)
        if s_code == nil then
            log.day_list(s_file,"request_map_share_code","new_share_code error", s_type, n_uin, uu.to_str(s_desc))
            return t_retCode.n_SYS_ERR, "new share code error"
        end

        log.day_list(s_file ,"request_map_share_code", "new code", s_type, n_uin, uu.to_str(s_code))

        n_specialMax    = this.special_exchange_max(t_taskConf.t_conf.t_specialCode, n_uin, n_mapId)
        n_verify        = t_shareCode.n_verify
        t_userData.share_code[s_type][n_mapId] = {
            ctime   = n_now,
            code    = s_code,
            num     = n_specialMax or t_shareCode.n_maxExchange,
            verify  = n_verify
        }
    end

    n_code, s_desc = t_user:set_share_mission_data(s_type, t_userData)
    if n_code ~= t_retCode.n_OK then
        log.day_list(s_file, "request_map_share_code", "save user code error", n_uin, uu.to_str(n_code), uu.to_str(s_desc), uu.to_str(t_userData.share_code))
        return n_code, s_desc
    end

    return t_retCode.n_OK, { code = s_code, verify = n_verify }
end

--------------------------------------------------------------
-- 说明：使用分享密码
-- 返回：n					状态码
--		ts 					描述
this.exchange_map_share_code = function()
    local t_params 			= ngx.ctx.t_params
    local s_code 			= t_params.code
    local s_type			= t_params.mission_type
    local n_uin 			= t_params.uin
    local t_taskConf 		= mis_data.t_share_mission[s_type]
    local t_shareCode		= t_taskConf.t_conf.t_shareCode or {}
    local s_file            = s_type .. '_code'
    local n_now				= mis_data.offset_now_v2(t_taskConf)
    local n_code, ts_desc
    local t_codeData, t_codeUser, t_codeUserData
    local s_codeUin, n_codeUin, b_valid, n_verify, n_retFriend, n_mapId, n_specialMax

    s_codeUin = string_sub(s_code, 1,#s_code - 6)

    if #s_code < this.CODE_MIN_LEN or not s_codeUin then
        log.day_list(s_file, "exchange_map_share_code", "s_code invalid", s_type, n_uin, s_code)
        return t_retCode.n_PARAM_ERR, 'code invalid'
    end

    n_codeUin = tonumber(s_codeUin, 16)
    t_codeUser = mis_data.get_user(n_codeUin)
    n_code, t_codeUserData = t_codeUser:get_share_mission_data(s_type)
    if n_code ~= t_retCode.n_OK then
        log.day_list(s_file ,"exchange_map_share_code", "get user data error", s_type, n_uin, n_code, uu.to_str(t_codeUserData))
        return t_retCode.n_MAP_SHARE_ERROR, 'get user data error'
    end

    -- 分享码不存在
    if not(t_codeUserData.share_code and t_codeUserData.share_code[s_type]) then
        log.day_list(s_file ,"exchange_map_share_code", "share data error", s_type, n_uin, n_code, uu.to_str(t_codeUserData))
        return t_retCode.n_MAP_SHARE_ERROR, 'get share data error'
    end

    t_codeData      = t_codeUserData.share_code[s_type]

    for k, v in pairs(t_codeData) do
        if v.code == s_code then
            if not this.is_valid_time(v.ctime, n_now, t_shareCode.n_expire) or not v.num then
                log.day_list(s_file ,"exchange_map_share_code", "expired", s_type, n_uin, n_code, uu.to_str(t_codeUserData))
                return t_retCode.n_MAP_SHARE_EXPIRE, 'share code expired'
            end

            if v.num < 1 then
                log.day_list(s_file ,"exchange_map_share_code", "num not enough", s_type, n_uin, n_code, uu.to_str(t_codeUserData))
                return t_retCode.n_MAP_SHARE_INVALID_TIMES, 'share code num not enough'
            end

            n_specialMax    = this.special_exchange_max(t_taskConf.t_conf.t_specialCode, n_codeUin, k)
            if not n_specialMax then
                if v[n_uin] and v[n_uin] >= t_shareCode.n_maxUserExchange then
                    log.day_list(s_file ,"exchange_map_share_code", "user num not enough", s_type, n_uin, n_code, uu.to_str(t_codeUserData))
                    return t_retCode.n_MAP_SHARE_INVALID_USER_TIMES, 'share code user num not enough'
                end

                v[n_uin]        = v[n_uin] or 0
                v[n_uin]        = v[n_uin] + 1
            end

            n_mapId         = k
            n_verify        = v.verify
            v.num           = v.num - 1
            b_valid         = true
            break
        end
    end

    if not b_valid then
        return t_retCode.n_MAP_SHARE_INVALID, 'share code invalid'
    end

    n_code, ts_desc = t_codeUser:set_share_mission_data(s_type, t_codeUserData)
    if n_code ~= t_retCode.n_OK then
        log.day_list(s_file, "exchange_map_share_code", "set_share_mission_data fail", s_type, n_uin, uu.to_str(n_code), uu.to_str(ts_desc))
        return n_code, ts_desc
    end

    -- 是否好友，特殊迷你号屏蔽好友功能
    if not n_specialMax then
        n_code = mis_bridge.friend_has_relation(n_uin, n_codeUin,3)
        if n_code ~= t_retCode.n_OK then
            -- 添加好友无需验证
            if n_verify and n_verify == 1 then
                n_code, ts_desc = mis_bridge.force_make_friend(n_codeUin, n_uin)
                if n_code ~= t_retCode.n_OK then
                    log.day_list(s_file, "force_make_friend", "failed", n_code, n_uin, t_codeData.uin)
                    n_retFriend = 1
                else
                    n_retFriend = 0
                end
            else
                -- 申请添加好友
                n_code, ts_desc = mis_bridge.apply_friend(n_uin, n_codeUin, 0)
                if n_code ~= t_retCode.n_OK then
                    log.day_list(s_file, "apply_friend", "failed", n_code, n_uin, t_codeData.uin)
                    n_retFriend = 1
                else
                    n_retFriend = 0
                end
            end
        end
    end

    log.day_list(s_file, "exchange_map_share_code", "ok", n_uin, n_codeUin, n_verify, n_retFriend, n_specialMax, s_code)

    return t_retCode.n_OK, { uin = n_codeUin, verify = n_verify, retFriend = n_retFriend, mapId = n_mapId }
end

--------------------------------------------------------------
-- 说明：加好友验证
-- 返回：n					状态码
--		ts 					描述
this.verify_add_friend = function()
    local t_params 			= ngx.ctx.t_params
    local s_code 			= t_params.code
    local s_type			= t_params.mission_type
    local n_uin 			= t_params.uin
    local n_verify          = t_params.verify
    local s_file            = s_type .. '_code'
    local n_code, ts_desc
    local t_codeData, t_codeUser, t_codeUserData
    local s_codeUin, n_codeUin

    s_codeUin = string_sub(s_code, 1,#s_code - 6)

    if #s_code < this.CODE_MIN_LEN or not s_codeUin then
        log.day_list(s_file, "verify_add_friend", "s_code invalid", s_type, n_uin, s_code)
        return t_retCode.n_PARAM_ERR, 'code invalid'
    end

    n_codeUin = tonumber(s_codeUin, 16)
    t_codeUser = mis_data.get_user(n_codeUin)
    n_code, t_codeUserData = t_codeUser:get_share_mission_data(s_type)
    if n_code ~= t_retCode.n_OK then
        log.day_list(s_file ,"verify_add_friend", "get user data error", s_type, n_uin, n_code, uu.to_str(t_codeUserData))
        return n_code, 'get user data error'
    end

    -- 分享码不存在
    if not(t_codeUserData.share_code and t_codeUserData.share_code[s_type]) then
        log.day_list(s_file ,"verify_add_friend", "share data error", s_type, n_uin, n_code, uu.to_str(t_codeUserData))
        return t_retCode.n_NO_DATA, 'get share data error'
    end

    t_codeData = t_codeUserData.share_code[s_type]
    for _, v in pairs(t_codeData) do
        if v.code == s_code then
            v.verify        = n_verify
            break
        end
    end

    n_code, ts_desc = t_codeUser:set_share_mission_data(s_type, t_codeUserData)
    if n_code ~= t_retCode.n_OK then
        log.day_list(s_file, "verify_add_friend", "set_data fail", s_type, n_uin, uu.to_str(n_code), uu.to_str(ts_desc))
        return n_code, ts_desc
    end

    return t_retCode.n_OK
end

return this